<template>
  <view class="option-kline-container">
    <view class="kline-tabs-wrap bg-theme">
      <view
        class="kline-tab-item"
        v-for="(item, index) in tabList"
        :key="index"
        :data-current="index"
        :data-value="item.value"
        :data-period="item.value"
        :data-type="item.chartType"
        :data-key="item.type"
        @click="lightChart.onPeriodChange"
        :class="{ active: index == subCurrent }"
      >
        <view class="kline-tab-label">
          {{ item.name }}
        </view>
      </view>
      <view class="kline-tabs-fixed-wrpas">
        <view class="kline-tab-item has-sub" @click.stop="showMore">
          <view class="kline-tab-label">
            <span class="label" :class="{ active: subCurrentItem.name }">{{
              subCurrentItem.name || $t("optionKline.labels[0]")
            }}</span>
            <u-icon
              class="arrow"
              name="arrow-down-fill"
              :size="arrowSize"
            ></u-icon>
          </view>

          <view class="kline-tab-more-wrap bg-theme" v-if="isMoreShow">
            <view
              class="kline-tab-more-item"
              hover-class="kline-tab-more-item-hover"
              hover-stay-time="50"
              v-for="(moreItem, moreIndex) in subItem"
              :data-value="moreItem.value"
              :data-current="moreIndex"
              :data-period="moreItem.value"
              :data-type="moreItem.chartType"
              :data-key="moreItem.type"
              :data-isMore="true"
              @click="lightChart.onPeriodChange"
              :key="moreIndex"
            >
              <span class="kline-more-label">{{ moreItem.name }}</span>
            </view>
          </view>
        </view>
        <view class="kline-tab-item has-sub" @click="showIndex">
          <view class="kline-tab-label">
            <span class="label">{{ $t("optionKline.default[0]") }}</span>
            <u-icon
              class="arrow"
              name="arrow-down-fill"
              :size="arrowSize"
            ></u-icon>
          </view>

          <view class="kline-tab-index-wrap bg-theme" v-if="isIndexShow">
            <view class="kline-tab-index-item">
              <view class="kline-index-label">{{
                $t("optionKline.default[5]")
              }}</view>
              <view class="kline-index-main">
                <view
                  class="kline-index-text"
                  hover-class="hover"
                  :class="{ active: subActive == 0 }"
                  :data-current="0"
                  :data-subactive="subActive"
                  @click.stop="lightChart.switchStudy"
                  hover-stay-time="50"
                >
                  MA
                </view>
                <view
                  class="kline-index-text"
                  hover-class="hover"
                  :class="{ active: subActive == 1 }"
                  :data-current="1"
                  :data-subactive="subActive"
                  @click.stop="lightChart.switchStudy"
                  hover-stay-time="50"
                >
                  BOLL
                </view>
              </view>
              <view
                class="kline-index-eye-wrap"
                :data-subactive="subActive"
                :class="{ brand: isSubActive }"
                @click.stop="lightChart.switchStudyVisible"
              >
                <u-icon
                  name="eye-fill"
                  :color="subActive !== null ? '#FD5B2C' : '#c3c3cd'"
                  size="40"
                ></u-icon>
              </view>
            </view>
          </view>
        </view>
      </view>
    </view>
    <view class="ma-labels bg-theme" v-if="subActive == 0">
      <view class="label-item ma5">MA5:{{ MA.ma5 }}</view>
      <view class="label-item ma10">MA10:{{ MA.ma10 }}</view>
      <view class="label-item ma30">MA30:{{ MA.ma30 }}</view>
    </view>
    <view class="boll-labels" v-if="subActive == 1">
      <view class="label-item middle">BOLL:{{ BOLL.middle }}</view>
      <view class="label-item up">UB:{{ BOLL.up }}</view>
      <view class="label-item down">LB:{{ BOLL.down }}</view>
    </view>
    <view
      class="tooltip bg-theme"
      v-if="tooltipVisible"
      :style="{
        left: `${toolPosition.left}px`,
        top: `${toolPosition.top + 30}px`,
      }"
    >
      <view class="line">
        <view class="label">
          {{ $t("optionKline.tooltip[0]") }}
        </view>
        <view class="value">
          {{ tooltipData.time }}
        </view>
      </view>
      <view class="line">
        <view class="label">
          {{ $t("optionKline.tooltip[1]") }}
        </view>
        <view class="value">
          {{ formatPrice(tooltipData.open) }}
        </view>
      </view>
      <view class="line">
        <view class="label">
          {{ $t("optionKline.tooltip[2]") }}
        </view>
        <view class="value">
          {{ formatPrice(tooltipData.close) }}
        </view>
      </view>
      <view class="line">
        <view class="label">
          {{ $t("optionKline.tooltip[3]") }}
        </view>
        <view class="value">
          {{ formatPrice(tooltipData.high) }}
        </view>
      </view>
      <view class="line">
        <view class="label">
          {{ $t("optionKline.tooltip[4]") }}
        </view>
        <view class="value">
          {{ formatPrice(tooltipData.low) }}
        </view>
      </view>
      <view class="line ma5" v-if="subActive == 0">
        <view class="label"> MA5: </view>
        <view class="value">
          {{ tooltipData.ma5 }}
        </view>
      </view>
      <view class="line ma10" v-if="subActive == 0">
        <view class="label"> MA10: </view>
        <view class="value">
          {{ tooltipData.ma10 }}
        </view>
      </view>
      <view class="line ma30" v-if="subActive == 0">
        <view class="label"> MA30: </view>
        <view class="value">
          {{ tooltipData.ma30 }}
        </view>
      </view>
      <view class="line middle" v-if="subActive == 1">
        <view class="label"> BOLL: </view>
        <view class="value">
          {{ tooltipData.middle }}
        </view>
      </view>
      <view class="line up" v-if="subActive == 1">
        <view class="label"> UB: </view>
        <view class="value">
          {{ tooltipData.up }}
        </view>
      </view>
      <view class="line down" v-if="subActive == 1">
        <view class="label"> LB: </view>
        <view class="value">
          {{ tooltipData.down }}
        </view>
      </view>
    </view>
    <!-- #ifdef APP-PLUS || H5 -->
    <view
      class="tv_chart_container"
      :prop="series"
      :change:prop="lightChart.updateData"
      id="tv_chart_container"
    ></view>
    <!-- #endif -->
    <!-- #ifndef APP-PLUS || H5 -->
    <view>非 APP、H5 环境不支持</view>
    <!-- #endif -->
  </view>
</template>

<script>
import FeedBase from "@/static/tradingView/datafeed.js";
import OptionTimeLine from "@/components/option/OptionTimeLine";
import OptionLineTabs from "@/components/option/OptionLineTabs";
import Event from "@/static/tradingView/event.js";
import KlineTabs from "./KlineTabs";
import tradeMixin from "@/pages/trade/trade.js";
import KlineDataTest from "../../test/klineDataTest.js";

const klineDataTest = new KlineDataTest();

export default {
  components: {
    OptionTimeLine,
    OptionLineTabs,
    KlineTabs,
  },
  props: {
    index_market: {
      type: String,
      default: "BTC/USDT",
    },
    matches_id: {
      type: String,
      default: "0",
    },
    /**
     * 组件页面显示和退出
     */
    show: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      arrowSize: "20",
      isMoreShow: false,
      isIndexShow: false,
      indexSelect: true,
      indexActive: 0, // default is MACD
      socketTask: null,
      current: 0,
      loading: false,
      period: "1min",
      series: {
        type: "series",
        data: [],
      },
      BOLL: {
        middle: NaN,
        up: NaN,
        down: NaN,
      },
      MA: {
        ma5: NaN,
        ma10: NaN,
        ma30: NaN,
      },
      tooltipVisible: false,
      toolPosition: {
        top: 0,
        left: 0,
      },
      tooltipData: {
        time: "",
        open: NaN,
        close: NaN,
        high: NaN,
        low: NaN,
        ma5: NaN,
        ma10: NaN,
        ma30: NaN,
        up: NaN,
        down: NaN,
        middle: NaN,
      },
      current: 0,
      subCurrent: 0,
      subCurrentShow: false,
      viceMapVisible: false,
      indexMapVisible: false,
      subMoreCurrent: 0, // sub more current index
      tabList: [
        // {
        //   name: this.$t('optionKline.default[1]'),
        //   id: 0,
        //   type: 'time',
        //   period: '1',
        //   value: "1",
        //   chartType: 3,
        // },
        {
          name: this.$t("optionKline.default[2]").replace("{time}", 1),
          id: 1,
          type: "1min",
          value: "1",
          period: "1m",
          chartType: 1,
        },
        {
          value: "5",
          name: this.$t("optionKline.default[2]").replace("{time}", 5),
          id: 2,
          type: "5min",
          period: "5m",
          chartType: 1,
        },
        {
          value: "30",
          type: "30min",
          name: this.$t("optionKline.default[2]").replace("{time}", 30),
          id: 3,
          period: "30m",
          chartType: 1,
        },
        {
          value: "60",
          type: "60min",
          name: this.$t("optionKline.default[3]").replace("{time}", 1),
          id: 4,
          chartType: 1,
          period: "1hour",
        },
        {
          value: "1D",
          type: "1day",
          name: this.$t("optionKline.default[4]").replace("{time}", 1),
          id: 5,
          period: "1D",
          chartType: 1,
        },
      ],
      subList: [
        {
          text: "MA",
        },
        {
          text: "BOLL",
        },
      ],
      subActive: 0,
    };
  },
  computed: {
    subItem() {
      return [
        {
          name: this.$t("optionKline.default[6]", { time: 1 }),
          type: "1week",
          value: "1W",
          period: "1W",
          chartType: 1,
        },
        {
          name: this.$t("optionKline.default[7]", { time: 1 }),
          value: "1M",
          type: "1mon",
          period: "1M",
          chartType: 1,
        },
      ];
    },
    subCurrentItem() {
      if (this.subMoreCurrent) {
        return this.subItem[this.subMoreCurrent];
      }
      return {};
    },
    showTimeline() {
      if (this.subCurrent == 0) {
        return true;
      }
      return false;
    },
    currentName() {
      return this.tabList[this.subCurrent].name;
    },
    currentLargerThemZero() {
      return this.subCurrent > 0;
    },
    isSubActive() {
      /**
       * don't touch this code, `null` can be equall to 0
       * null == 0 ?  output: false
       * null > 0 ?   output: false
       * is null >= 0 also output false ?
       * no, the output is `true`
       */
      if (this.subActive == 0 || this.subActive > 0) {
        return true;
      }
      return false;
    },
  },
  watch: {
    show() {
      if (this.show) {
        this.fetchHistory();
      } else {
        this.close();
      }
    },
  },
  mounted() {
    this.fetchHistory();
    if (this.theme) {
      // this.chartConfig.theme = this.theme == 'light' ? 'Light' : 'Dark';
    }
  },
  beforeDestroy() {
    this.close();
  },
  methods: {
    formatPrice(price) {
      let trade = new tradeMixin(this);
      return trade.formatPrice(price, this.index_market);
    },
    showIndex() {
      this.isMoreShow = false;
      this.isIndexShow = !this.isIndexShow;
    },
    showMore() {
      this.isIndexShow = false;
      this.isMoreShow = !this.isMoreShow;
    },
    onSubTabClick(current) {
      this.subCurrent = null;
      this.subMoreCurrent = current;
      this.isIndexShow = false;
    },
    setBollData(data) {
      Object.assign(this.BOLL, data);
    },
    setTooltipPosition(data) {
      this.toolPosition.top = data.top;
      this.toolPosition.left = data.left;
    },
    setTooltipData(value) {
      Object.assign(this.tooltipData, value);
    },
    setToolTipVisible({ visible }) {
      this.tooltipVisible = visible;
    },
    showIndex() {
      this.isMoreShow = false;
      this.isIndexShow = !this.isIndexShow;
    },
    showSubCurrent(e) {
      let current = e.currentTarget.dataset.current;
      if (current === this.current) {
        this.subCurrentShow = !this.subCurrentShow;
      } else {
        this.current = current;
        this.subCurrentShow = true;
      }
    },
    hideSubCurrent() {
      this.subCurrentShow = false;
    },
    setSubcurrent({ index }) {
      this.subCurrent = index;
      this.subMoreCurrent = null;
      this.hideSubCurrent();
    },
    switchViceMapVisible() {
      this.viceMapVisible = !this.viceMapVisible;
    },
    setSubActive(index) {
      this.subActive = index;
      this.hideSubCurrent();
    },
    // 修改当前period
    setCurrent(index) {
      this.current = Number(index);
    },
    serPeriod(period) {
      this.period = period;
    },
    setMa(day, value) {
      // #ifdef APP-PLUS
      value = day.value;
      day = day.day;
      // #endif
      this.MA[`ma${day}`] = parseFloat(value).toFixed(4);
    },
    periodChange(period) {
      this.$emit("onPeriodChange", period);
    },
    fetchHistory() {
      const params = {
        symbol: this.index_market,
        period: this.period,
        currency_match_id: this.matches_id,
      };
      this.close();
      const url = "/market/kline";
      this.loading = true;
      this.$u
        .get(url, params)
        .then((res) => {
          this.loading = false;
          if (res.code == 1) {
            this.connect();
            if (process.env.NODE_ENV === "development") {
              setTimeout(() => {
                klineDataTest.test(res.data);
              }, 1000);
            }
            this.series = Object.assign({}, this.series, {
              type: "series",
              data: res.data,
            });
            let lastData = res.data[this.series.data.length - 1];
            Event.emit("close", { type: this.period, close: lastData.close });
          }
        })
        .catch((err) => {
          this.loading = false;
        });
    },
    connect() {
      const params = {
        type: "sub",
        params: "KLINE." + this.index_market,
      };
      const _this = this;
      this.socketTask = uni.connectSocket({
        url: this.$config.wss,
        complete: () => {},
      });
      this.socketTask.onOpen(() => {
        this.socketTask.send({
          data: JSON.stringify(params),
        });
      });
      this.socketTask.onMessage((res) => {
        const data = JSON.parse(res.data);
        _this.updateSeriesData(data);
        // handle data
      });
      this.socketTask.onClose((res) => {
        // console.log('关闭K线socket')
      });
    },
    close() {
      if (this.socketTask) {
        this.socketTask.close();
      }
    },
    systemlog(msg) {
      this.$u.toast(msg);
      console.log(msg);
    },
    updateSeriesData(data) {
      if (data.type == "KLINE") {
        if (data.kline.period == this.period) {
          if (this.loading) return;
          this.series = Object.assign({}, this.series, {
            type: "item",
            data: data.kline,
          });
          Event.emit("close", { type: this.period, close: data.kline.close });
        }
      }
    },
  },
};
</script>

<script module="lightChart" lang="renderjs">
import dayjs from 'dayjs';
import store from '@/store/index.js';


// 图标库实例化后储存的函数
let chart = null
let widget = null;
let seriesData = [] // 存储历史K线数据
let lineMA5Series = null // 5日均线
let lineMA10Series = null // 10日均线
let lineMA30Series = null // 30日均线
let candlestickSeries = null
// 指标显示
let maVisible = true
let bollVisible = false
// 进入页面默认展示的产品
// let index_market = 'btcusdt';
// 进入页面默认展示的产品周期 1min k线
let index_activeCycle = 1;
let ttimer = null
let v = null
let width = null
let height = null
let fixedPoints = 4 // MA指标、BOLL指标计算精确小数位
let bollLine = {
  up: null, // 上轨
  middle: null, // 中轨
  down: null // 下轨
}

const twoMatchPoint = []

export default {
  created() {
    v = this
    maVisible = true
  },
  mounted() {
    chart = null
    lineMA5Series = null // 5日均线
    lineMA10Series = null // 10日均线
    lineMA30Series = null // 30日均线
    this.loadChart()
  },
  methods: {
    loadChart() {
      if (window.LightweightCharts) {
        this.init()
      } else {
        // 动态引入较大类库避免影响页面展示
        const script = document.createElement('script')
        // view 层的页面运行在www根目录, 其相对路径相对于www计算
        script.src = 'static/js/lightweight-charts.standalone.production.js'
        script.onload = this.init.bind(this)
        document.head.appendChild(script) // Wonderful
      }
    },
    init() {
      let theme = store.state.theme
      let layout = {
        backgroundColor: theme === 'dark' ? '#0f0e13' : '#fff',
        textColor: theme === 'dark' ? '#8e8d92' : '#8E8D92',
        fontSize: 12,
      }

      let c = document.getElementsByClassName('option-kline-container')[0]
      let container = document.getElementById('tv_chart_container')
      chart = LightweightCharts.createChart(container, {
        width: c.clientWidth,
        height: c.clientHeight - 25
      })
      width = c.clientWidth
      height = c.clientHeight - 25
      this.applyTimeScale('1min')
      chart.applyOptions({
          localization: {
            // dateFormat: 'yyyy/MM/dd',
            timeFormatter: businessDayOrTimestamp => {
              if (LightweightCharts.isBusinessDay(businessDayOrTimestamp)) {
                  // return 'Format for business day';
              }
              return dayjs(businessDayOrTimestamp).format('YYYY-MM-DD HH:mm:ss')
            },
          },
          grid: {
            vertLines: {
              color: 'rgba(142,141,146, 0.5)',
              style: 1,
              visible: true,
            },
            horzLines: {
              color: 'rgba(142,141,146, 0.5)',
              style: 1,
              visible: true,
            },
          },
          layout: layout,
          priceScale: {
            borderVisible: false,
          },
          timeScale: {
            fixLeftEdge: true,
            borderVisible: false,
            fixRightEdge: true,
          }
      });
      chart.subscribeClick(this.handleClick)
      chart.subscribeCrosshairMove(this.handleCrossMove)
      candlestickSeries = chart.addCandlestickSeries({
        upColor: '#19ab62',
        downColor: '#ee4e55'
      })
    },
    applyTimeScale(period) {
      if (!chart) return
      if (period == '1day') {
        chart.applyOptions({
          timeScale: {
          	timeVisible: true,
            secondsVisible: true,
            tickMarkFormatter: (time) => {
              // const date = new Date(time)
              // return `${date.getHours() + 1}:${date.getMinutes() + 1}`
              return dayjs(time).format('YYYY/MM/DD')
            },
          }
        })
      } else {
        chart.applyOptions({
          timeScale: {
          	timeVisible: true,
            secondsVisible: true,
            tickMarkFormatter: (time) => {
              // const date = new Date(time)
              // return `${date.getHours() + 1}:${date.getMinutes() + 1}`
              return dayjs(time).format('MM-DD HH:mm')
            },
          }
        })
      }
      // if (period == '1min' || period == "5min") {
      //   chart.applyOptions({
      //     timeScale: {
      //     	timeVisible: true,
      //       secondsVisible: true,
      //       tickMarkFormatter: (time) => {
      //         const date = new Date(time)
      //         return `${date.getHours() + 1}:${date.getMinutes() + 1}`
      //       },
      //     }
      //   })
      // } else if (period == '30min') {
      //   chart.applyOptions({
      //     timeScale: {
      //     	timeVisible: true,
      //       secondsVisible: true,
      //       tickMarkFormatter: (time) => {
      //         const date = new Date(time)
      //         return `${date.getDate()}`
      //       },
      //     }
      //   })
      // }
    },

    /**
     * 计算N日收盘价标准差
     * @param {Object} data
     */
    calculateMD(data, N = 20) {
      const length = data.length
      let result = []
      for (let i = 0; i < length; i++) {
        if (i < N - 1) {
          continue
        }
        let sum = 0
        for (let j = 0; j < N; j++) {
          sum += Number(data[i - j].close)
        }
        let average = sum / N // N 日平均数
        let averageSum = 0
        for (let j = 0; j < N; j++) {
          averageSum += Math.pow(Number(data[i - j].close) - average, 2)
        }
        if (averageSum > 0) {
          let a = Math.sqrt(averageSum / N)
          result.push(Number((a).toFixed(fixedPoints)))
        }
      }
      return result
    },
    /**
     * 计算Bollineger指标
     */
    calculateBoll(data, day = 20) {
      // 中轨线数据
      let ma20series = this.calculateMA(day, data)
      const length = ma20series.length
      // 计算20日收盘价的标准差
      let mds = this.calculateMD(data)
      // 上轨 = 中轨 + 2 * MD (两倍的标准差)
      let upLine = []
      let downLine = []
      for (let i = 0; i < length; i++) {
        let md = mds[i]
        let item = ma20series[i]
        upLine.push({ time: item.time, value: Number((item.value + 2 * md).toFixed(fixedPoints)) })
        downLine.push({ time: item.time, value: Number((item.value - 2 * md).toFixed(fixedPoints)) })
      }
      return { middle: ma20series, up: upLine, down: downLine }
    },
    /**
     * 计算MA(Moving Average)指标
     *
     * @param {Object} dayCount
     * @param {Object} data
     */
    calculateMA(dayCount, data) {
      var result = [];
      for (var i = 0, len = data.length; i < len; i++) {
          if (i < dayCount - 1) {
              // result.push();
              continue;
          }
          var sum = 0;
          for (var j = 0; j < dayCount; j++) {
              sum += Number(data[i - j].close);
          }
          result.push({ time: data[i].time, value: Number((sum / dayCount).toFixed(fixedPoints)) });
      }
      return result;
    },
    closeBoll() {
      bollVisible = false
      let keys = Object.keys(bollLine)
      for (let key of keys) {
        if (bollLine[key]) {
          chart.removeSeries(bollLine[key])
          bollLine[key] = null
        }
      }
    },
    createBoll() {
      if (!chart) return // 防止空指针
      let boll = this.calculateBoll(seriesData)
      let latestData = {
        up: null,
        down: null,
        middle: null
      }
      // 中轨
      if (!bollLine.middle) {
        bollLine.middle = chart.addLineSeries({
          color: '#1683e2',
          lineWidth: 1,
          priceLineVisible: false, // price line visible
          lastValueVisible: false, // price label visible
        })
      }

      if (boll.middle.length > 0) {
        bollLine.middle.setData(boll.middle)
        latestData.middle = boll.middle[boll.middle.length - 1].value.toFixed(fixedPoints)
      } else if (bollLine.middle) {
        chart.removeSeries(bollLine.middle)
        bollLine.middle = null
      }

      // 上轨
      if (!bollLine.up) {
        bollLine.up = chart.addLineSeries({
          color: '#bd9613',
          lineWidth: 1,
          priceLineVisible: false, // price line visible
          lastValueVisible: false, // price label visible
        })
      }
      if (boll.up.length > 0) {
        bollLine.up.setData(boll.up)
        latestData.up = boll.up[boll.up.length - 1].value.toFixed(fixedPoints)
      } else if (bollLine.up) {
        chart.removeSeries(bollLine.up)
        bollLine.up = null
      }

      // 下轨
      if (!bollLine.down) {
        bollLine.down = chart.addLineSeries({
          color: '#b209ac',
          lineWidth: 1,
          priceLineVisible: false, // price line visible
          lastValueVisible: false, // price label visible
        })
      }
      if (boll.down.length > 0) {
        // 刷新下轨数据
        bollLine.down.setData(boll.down)
        latestData.down = boll.down[boll.down.length - 1].value.toFixed(fixedPoints)
      } else if (bollLine.down) {
        chart.removeSeries(bollLine.down)
        bollLine.down = null
      }
      // #ifdef APP-PLUS
        UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
          cid: v._$id,
          method:'setBollData',
          args: latestData
        })
      // #endif
      // #ifdef H5
      this.setBollData(latestData)
      // #endif
      bollVisible = true
    },
    createMA() {
      if (!chart) return
      // 创建[5, 10, 30]日均线
      let maSeries = this.calculateMA(5, seriesData)
      let ma10Series = this.calculateMA(10, seriesData)
      let ma30Series = this.calculateMA(30, seriesData)
      if (!lineMA5Series) {
        lineMA5Series = chart.addLineSeries({
          color: '#b19228',
          lineWidth: 1,
          priceLineVisible: false, // price line visible
          lastValueVisible: false, // price label visible
        });
      }
      if (!lineMA10Series) {
        lineMA10Series = chart.addLineSeries({
          color: '#1783de',
          lineWidth: 1,
          priceLineVisible: false, // price line visible
          lastValueVisible: false, // price label visible
        })
      }
      if (!lineMA30Series) {
        lineMA30Series = chart.addLineSeries({
          color: '#91208a',
          lineWidth: 1,
          priceLineVisible: false, // price line visible
          lastValueVisible: false, // price label visible
        });
      }

      if (maSeries.length > 0) {
        lineMA5Series.setData(maSeries)
      } else {
        // series 不存在，则移除series
        chart.removeSeries(lineMA5Series)
        lineMA5Series = null
      }
      if (ma10Series.length > 0) {
        lineMA10Series.setData(ma10Series)
      } else {
        chart.removeSeries(lineMA10Series)
        lineMA10Series = null
      }
      if (ma30Series.length > 0) {
        lineMA30Series.setData(ma30Series)
      } else {
        chart.removeSeries(lineMA30Series)
        lineMA30Series = null
      }

      let days = [5, 10, 30]
      for (let day of days) {
        let value = NaN
        if (day == 5 && maSeries.length > 0) {
          value = maSeries[maSeries.length - 1].value
        } else if (day == 10 && ma10Series.length > 0) {
          value = ma10Series[ma10Series.length - 1].value
        } else if (day == 30 && ma30Series.length > 0) {
          value = ma30Series[ma30Series.length - 1].value
        }
        // #ifdef APP-PLUS
          UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
            cid: v._$id,
            method:'setMa',
            args: {day: day, value: value}
          })
        // #endif
        // #ifdef H5
        this.setMa(day, value)
        // #endif
      }
      maVisible = true
    },
    /**
     * 更新BOLL指标
     *
     * @param {Object} item
     */
    updateBoll(item, N = 20) {
      if (seriesData.length >= N) {
        let latestData = {middle: null, up: null, down: null}
        let latestSeriesData = seriesData.slice(seriesData.length - 2)
        // 单位是秒
        let interval = Number(latestSeriesData[1].time) - Number(latestSeriesData[0].time)
        let latestInterval = Number(item.time) - Number(latestSeriesData[1].time)
        if (latestInterval == 0) {
          seriesData.pop() // 取下最后一个值
          seriesData.push(item) // 将新数据插入
        } else if(latestInterval > 0){
          seriesData.push(item)
        }
        let s = seriesData.slice(seriesData.length - N)
        let point = this.calculateBoll(s)
        if (point.middle.length > 0) {
          latestData.middle = point.middle[0].value.toFixed(fixedPoints)
          bollLine.middle.update(point.middle[0])
        }
        if (point.up.length > 0) {
          latestData.up = point.up[0].value.toFixed(fixedPoints)
          bollLine.up.update(point.up[0])
        }
        if (point.down.length > 0) {
          latestData.down = point.down[0].value.toFixed(fixedPoints)
          bollLine.down.update(point.down[0])
        }
        // #ifdef APP-PLUS
          UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
            cid: v._$id,
            method:'setBollData',
            args: latestData
          })
        // #endif
        // #ifdef H5
        this.setBollData(latestData)
        // #endif
      }
    },
    /**
     * 更新MA均线数据，只计算最新点的N日均线
     * @param {Object} item
     */
    updateMA(item) {
      // 更新5日均线
      let days = [5, 10, 30]
      for (let day of days) {
        if (seriesData.length > day) {
          let latestSeriesData = seriesData.slice(seriesData.length - 2)
          // 单位是秒
          let interval = Number(latestSeriesData[1].time) - Number(latestSeriesData[0].time)
          let latestInterval = Number(item.time) - Number(latestSeriesData[1].time)
          if (latestInterval == 0) {
            seriesData.pop() // 取下最后一个值
            seriesData.push(item) // 将新数据插入
          } else if(latestInterval > 0){
            seriesData.push(item)
          }
          let s = seriesData.slice(seriesData.length - day) // 取倒数4个值 + 最新的一个值，计算
          let point = this.calculateMA(day, s)
          // #ifdef APP-PLUS
            UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
              cid: v._$id,
              method:'setMa',
              args: {day: day, value: point[0].value}
            })
          // #endif

          // #ifdef H5
          this.setMa(day, point[0].value)
          // #endif
          if (day == 5) {
           if (lineMA5Series && point.length > 0) {
             lineMA5Series.update(point[0])
           }
          } else if (day == 10) {
            if (lineMA10Series && point.length > 0) {
              lineMA10Series.update(point[0])
            }
          } else if (day == 30) {
            if (lineMA30Series && point.length > 0) {
              lineMA30Series.update(point[0])
            }
          }
        }
      }
    },
    hideBoll() {
      bollVisible = false
      let keys = Object.keys(bollLine)
      for (let key of keys) {
        let line = bollLine[key]
        if (line) {
          line.applyOptions({
            visible: maVisible
          })
        }
      }
    },
    hideMA() {
      maVisible = false
      let lines = [lineMA5Series, lineMA10Series, lineMA30Series]
      for (let line of lines) {
        if (line) {
          line.applyOptions({
            visible: maVisible
          })
        }
      }
    },
    destroyMA() {
      if (chart) {
        if (lineMA5Series) {
          chart.removeSeries(lineMA5Series)
          lineMA5Series = null
        }
        if (lineMA10Series) {
          chart.removeSeries(lineMA10Series)
          lineMA10Series = null
        }
        if (lineMA30Series) {
          chart.removeSeries(lineMA30Series)
          lineMA30Series = null
        }
      }
      maVisible = false
    },
    switchStudyVisible(e, ownerInstance) {
      if (!maVisible && !bollVisible) return
      if (maVisible) {
        this.destroyMA()
      }
      if (bollVisible) {
        this.closeBoll()
      }
      ownerInstance.callMethod('setSubActive', null)

      // const current = 0
      // const subActive = e.currentTarget.dataset.subactive
      // if (current == subActive) {
      //   ownerInstance.callMethod('setSubActive', null)
      // } else {
      //   ownerInstance.callMethod('setSubActive', current)
      // }
      // if (current == 0) {
      //   // 修改MA指标的visible
      //   maVisible = !maVisible
      //   let lines = [lineMA5Series, lineMA10Series, lineMA30Series]
      //   for (let line of lines) {
      //     if (line) {
      //       line.applyOptions({
      //         visible: maVisible
      //       })
      //     }
      //   }
      // }
    },
    switchStudy(e, ownerInstance) {
      const current = e.target.dataset.current
      const subActive = e.target.dataset.subactive
      if (current == 0) {
        if (maVisible) {
          this.bollVisible = false
          return
        }
        if (bollVisible) {
          this.closeBoll()
        }
        this.createMA()
      } else if (current == 1) {
        if (bollVisible) {
          maVisible = false
          return
        }
        if (maVisible) {
          this.destroyMA()
        }
        this.createBoll()
      }
      if (current == subActive) {
        ownerInstance.callMethod('setSubActive', null)
      } else {
        ownerInstance.callMethod('setSubActive', current)
      }
    },
    handleCrossMove(param) {
      if (!param.time || param.point.x < 0 || param.point.x > width || param.point.y < 0 || param.point.y > height) {
        // #ifdef H5
        this.setToolTipVisible({visible: false})
        // #endif
        // #ifdef APP-PLUS
          UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
            cid: v._$id,
            method:'setToolTipVisible',
            args: {visible: false}
          })
        // #endif
        return;
      }
      var toolTipWidth = 160;
      var toolTipHeight = 154;
      var toolTipMargin = 15;

      var y = param.point.y;
      var left = param.point.x + toolTipMargin;
      if (left > width - toolTipWidth) {
        left = param.point.x - toolTipMargin - toolTipWidth;
      }
      var top = y + toolTipMargin;
      if (top > height - toolTipHeight) {
        top = y - toolTipHeight - toolTipMargin;
      }

      let dateStr = param.time
      let candleItem = param.seriesPrices.get(candlestickSeries)
      let options = {}
      if (maVisible) {
        let ma5Price = param.seriesPrices.get(lineMA5Series) || NaN
        if (ma5Price) {
          ma5Price = ma5Price.toFixed(fixedPoints)
        }
        let ma10Price = param.seriesPrices.get(lineMA10Series) || NaN
        if ( ma10Price ) {
          ma10Price = ma10Price.toFixed(fixedPoints)
        }
        let ma30Price = param.seriesPrices.get(lineMA30Series) || NaN
        if (ma30Price) {
          ma30Price = ma30Price.toFixed(fixedPoints)
        }
        Object.assign(options, { ma5:ma5Price, ma10: ma10Price, ma30: ma30Price,})
      }
      if (bollVisible) {
        let keys = Object.keys(bollLine)
        for (let key of keys) {
          let line = bollLine[key]
          let value = param.seriesPrices.get(line)
          if (value) {
            options[key] = value.toFixed(fixedPoints)
          }
        }
      }

      let data = Object.assign({},
      candleItem,
      options,
      { time: dayjs(dateStr).format('YYYY-MM-DD HH:mm') })
      // #ifdef H5
      this.setTooltipPosition({top, left})
      this.setToolTipVisible({visible: true})
      this.setTooltipData(data)
      // #endif
      // #ifdef APP-PLUS
        UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
          cid: v._$id,
          method:'setTooltipPosition',
          args: {top, left}
        })
        UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
          cid: v._$id,
          method:'setToolTipVisible',
          args: {visible: true}
        })
        UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
          cid: v._$id,
          method:'setTooltipData',
          args: data
        })
      // #endif
    },
    /**
     * 处理K线点击
     * @param {Object} param
     */
    handleClick(param) {
      // if (!param.point) {
      //   return;
      // }
      // let dateStr = param.time
      // let price = param.seriesPrices.get(candlestickSeries)
      // console.log(`date = ${dateStr}, price = ${JSON.stringify(price)}`)
      // console.log(JSON.stringify(param))
      // console.log(`An user clicks at (${param.point.x}, ${param.point.y}) point, the time is ${param.time}`);
    },
    /**
     * 接收视图层数据更新
     *
     * @param {Object} newValue
     * @param {Object} oldValue
     * @param {Object} ownerInstance
     * @param {Object} instance
     */
    updateData(newValue, oldValue, ownerInstance, instance) {
      if (this.series.type == 'series') {
        seriesData = [...this.series.data]
        const match = ['BTC', 'ETH']
        const [first] = seriesData
        if (chart) {
          if (first) {
            let flag = match.some(b => b == first['base-currency']);
            let precision = flag ? 2 : 4;
            fixedPoints = flag ? 2 : 4;
            let miMove = flag ? 0.01 : 0.0001;
            candlestickSeries.applyOptions({
              priceFormat: {
                  type: 'price',
                  precision: precision,
                  minMove: miMove,
              },
            })
          }

          candlestickSeries.setData(this.series.data)
          if (maVisible) {
            this.createMA()
          } else {
            this.createBoll()
          }
          chart.timeScale().resetTimeScale();
          return
        }
        /**
         * chart还没有创建
         */
        this.loadChart()
        setTimeout(() => {
          if (first) {
            let flag = match.some(b => b == first['base-currency']);
            let precision = flag ? 2 : 4;
            fixedPoints = flag ? 2 : 4;
            let miMove = flag ? 0.01 : 0.0001;
            candlestickSeries.applyOptions({
              priceFormat: {
                  type: 'price',
                  precision: precision,
                  minMove: miMove,
              },
            })
          }
          candlestickSeries.setData(this.series.data)
          if (maVisible) {
            this.createMA()
          } else {
            this.createBoll()
          }
          chart.timeScale().resetTimeScale();
        }, 300)
      } else if (newValue.type == 'item') {
        if (!candlestickSeries) return;
        candlestickSeries.update(this.series.data)
        if (maVisible) {
          this.updateMA(this.series.data)
        } else if (bollVisible) {
          this.updateBoll(this.series.data)
        }
      }
    },
    testClick(e, ownerInstance) {
      let a = 'hello world'
      ownerInstance.callMethod('systemlog', a)
    },
    onPeriodChange(e, ownerInstance) {
      const {current, period, key, type, ismore } = e.currentTarget.dataset;
      if (ismore) {
        console.log('ismore = ', ismore)
        ownerInstance.callMethod('onSubTabClick', current)
      } else {
        ownerInstance.callMethod('setSubcurrent', {
          index: current
        })
      }

      // 设置当前period
      ownerInstance.callMethod('setCurrent', current)
      // if (current == 0) {
      //   ownerInstance.callMethod('periodChange', key)
      //   return;
      // }

      ownerInstance.callMethod('serPeriod', key)
      ownerInstance.callMethod('fetchHistory', {})
      ownerInstance.callMethod('periodChange', key);
      this.applyTimeScale(key)
    },
  },

}
</script>

<style lang="less" scoped>
.ma-labels {
  position: absolute;
  top: 68rpx;
  left: 4rpx;
  display: flex;
  flex-direction: row;
  z-index: 100;
  .label-item {
    font-size: 22rpx;
    margin-right: 10rpx;
    &.ma5 {
      color: #b19228;
    }
    &.ma10 {
      color: #1783de;
    }
    &.ma30 {
      color: #91208a;
    }
  }
}

.boll-labels {
  position: absolute;
  top: 68rpx;
  left: 4rpx;
  display: flex;
  flex-direction: row;
  z-index: 100;
  .label-item {
    font-size: 22rpx;
    margin-right: 10rpx;
    &.up {
      color: #b19228;
    }
    &.middle {
      color: #1783de;
    }
    &.down {
      color: #91208a;
    }
  }
}

.up {
  color: #b19228;
}
.middle {
  color: #1783de;
}
.down {
  color: #91208a;
}

.ma5 {
  color: #b19228;
}
.ma10 {
  color: #1783de;
}
.ma30 {
  color: #91208a;
}
.option-kline-container {
  width: 100%;
  height: 100%;
  min-height: 400rpx;
  position: relative;
  #tv_chart_container {
    height: calc(100% - 66rpx);
    max-height: 375px;
    width: 100%;
    min-height: 400rpx;
  }
}
.button-hover {
  background-color: @bg-color-gray;
}
.option-kline-tabs {
  display: flex;
  font-weight: bold;
  position: relative;
  font-size: 24rpx;
  .kline-tabs-item {
    padding: 10rpx 0;
    &:first-child {
      padding: 10rpx 30rpx;
    }
    &.brand {
      color: @brand-color;
    }
    .tabdown-icon {
      margin-left: 10rpx;
    }

    .kline-tabs-sub {
      color: @text-main-color;
      background-color: @white;
      padding: 10rpx;
      position: absolute;
      bottom: -10rpx;
      left: 10rpx;
      right: 10rpx;
      transform: translateY(100%);
      display: flex;
      flex-flow: row wrap;
      justify-content: space-between;
      white-space: nowrap;
      z-index: 101;
      &.index {
        display: flex;
        flex-flow: column nowrap;
        padding: 20rpx;
        .kline-tabs-sub-item {
          display: flex;
          justify-content: space-between;
          margin-bottom: 20rpx;
          .kline-tabs-label {
            flex: 0 0 auto;
            width: 200rpx;
            text-align: center;
            display: flex;
            align-items: center;
            justify-content: center;
          }
          .kline-tabs-sub-main {
            flex: 1;
            display: flex;
            flex-flow: row wrap;
            justify-content: space-between;
            .tabs-sub-main-item {
              flex: 0 0 50%;
              text-align: center;
              padding: 10rpx 0;
              &.active {
                color: @brand-color;
              }
            }
          }
          .tabs-sub-visible {
            flex: 0 0 auto;
            width: 200rpx;
            text-align: center;
            color: #c3c3cd;
            &.brand {
              color: @brand-color;
            }
          }
        }
      }
      .kline-sub-tab-mask {
        z-index: 100;
        position: fixed;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
      }
      .tabs-sub-item {
        width: 120rpx;
        display: flex;
        justify-content: center;
        padding: 10rpx 0;
        align-items: center;
        &.active {
          color: @brand-color;
        }
      }
    }
  }
}

.tooltip {
  position: absolute;
  top: 44rpx;
  left: 30rpx;
  width: 320rpx;
  z-index: 199;
  background-color: @white;
  color: @text-tips-color;
  padding: 30rpx;
  border-radius: 16rpx;
  border: 2rpx solid @border-color;
  font-size: 20rpx;
  .line {
    display: flex;
    justify-content: space-between;
    .label {
    }
    .value {
    }
  }
}

.kline-tabs-wrap {
  font-size: 24rpx;
  display: flex;
  flex-flow: row nowrap;
  align-items: center;
  justify-content: space-between;
  padding: 0 30rpx;
  background: @white;
  color: #8e8d92;
  font-weight: bold;
  position: relative;
  z-index: 101;
  .kline-tab-item {
    height: 66rpx;
    line-height: 66rpx;
    text-align: center;
    &.has-sub {
      margin-right: 20rpx;
    }
    &:last-child {
      margin-right: 0;
    }
    &.active {
      color: #19ab62;
    }
    .kline-tab-label {
      .label {
        &.active {
          color: @brand-color;
        }
      }
    }
  }

  .kline-tabs-fixed-wrpas {
    display: flex;
    .kline-tab-item {
    }
    .arrow {
      transform: scale(0.63);
      margin-left: 8rpx;
    }
  }
  .kline-tab-more-wrap {
    z-index: 110;
    display: flex;
    flex-flow: row wrap;
    background-color: @white;
    position: absolute;
    left: 10rpx;
    right: 10rpx;
    bottom: 0rpx;
    transform: translateY(100%);
    padding: 10rpx;
    .kline-tab-more-item {
      width: 120rpx;
      &.kline-tab-more-item-hover {
        background-color: @bg-color-gray;
      }
    }
  }

  .kline-tab-index-wrap {
    position: absolute;
    left: 10rpx;
    right: 10rpx;
    bottom: -10rpx;
    transform: translateY(100%);
    padding: 10rpx;
    background-color: @white;
    padding: 0 30rpx;
    .kline-tab-index-item {
      display: flex;
      justify-content: space-between;
      .kline-index-label {
        flex: 0 0 auto;
        width: 200rpx;
      }
      .kline-index-main {
        flex: 1;
        display: flex;
        flex-flow: row wrap;
        .kline-index-text {
          width: 100rpx;
          &.active {
            color: @brand-color;
          }
        }
      }
      .kline-index-eye-wrap {
        flex: 0 0 auto;
        width: 200rpx;
        font-size: 30rpx;
      }
    }
  }
}
</style>
